package me.sealer.demo;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 功能描述： 生成地址TreeView所需数据源
 *
 * @author sealer
 * @email 1178884049@qq.com
 * @date 2019年09月24日 10时03分22秒
 */
public class AddressTree {
    /**
     * 生成子节点和父节点的key-value映射
     *
     * @param list        格式为01020304， 每两位代表一级行政区划， 具体程度不限， 如010101可以代表 中国 北京市 大兴区 黄村镇
     * @param codeNameMap code&name 映射 如： 01=中国
     * @param jsonPretty
     * @return 符合bootstrap treeView的json串
     */
    public static String genRootNodesJsonStr(List<SourceNode> list, Map<String, String> codeNameMap, boolean jsonPretty) throws JsonProcessingException {
        NodesCache nodesCache = new NodesCache();

        for (SourceNode sourceNode : list) {
            String id = sourceNode.getId();
            String url = sourceNode.getUrl();
            // 之所以是魔法数2， 是因为每两位代表一级行政规划
            if (id.length() < 2) {
                throw new RuntimeException("源数据有误， id长度低于2位。");
            }
            while (id.length() > 2) {
                AddressNode addressNode = new AddressNode();
                addressNode.setId(id);
                addressNode.setUrl(url);
                addressNode.setName(codeNameMap.get(id));
                // cache
                addressNode = nodesCache.cacheIfAbsent(addressNode);

                String parentId = id.substring(0, id.length() - 2);
                AddressNode parentAddressNode = new AddressNode();
                parentAddressNode.setId(parentId);
                parentAddressNode.setName(codeNameMap.get(parentId));

                // cache
                parentAddressNode = nodesCache.cacheIfAbsent(parentAddressNode);

                if (!parentAddressNode.getAddressNodes().contains(addressNode)) {
                    parentAddressNode.getAddressNodes().add(addressNode);
                }

                id = id.substring(0, id.length() - 2);
            }
        }

        List<AddressNode> resultAddressNodes = nodesCache.addressNodes()
                .stream()
                .filter(n -> n.getId().length() == 2)
                .collect(Collectors.toList());

        String jsonStr = new ObjectMapper().writeValueAsString(resultAddressNodes);
        return JSON.toJSONString(JSON.parseArray(jsonStr), jsonPretty);
    }

    /**
     * 生成子节点和父节点的key-value映射
     *
     * @param list        格式为01020304， 每两位代表一级行政区划， 具体程度不限， 如010101可以代表 中国 北京市 大兴区 黄村镇
     * @param codeNameMap code&name 映射 如： 01=中国
     * @return 符合bootstrap treeView的json串
     */
    public static String genRootNodesJsonStr(List<SourceNode> list, Map<String, String> codeNameMap) throws JsonProcessingException {
        return genRootNodesJsonStr(list, codeNameMap, false);
    }
}

class AddressNode {
    private String id;
    private String name;
    private String url;
    private List<AddressNode> addressNodes = new ArrayList<>();

    public AddressNode() {
    }

    public AddressNode(String id, String name, String url, List<AddressNode> addressNodes) {
        this.id = id;
        this.name = name;
        this.url = url;
        this.addressNodes = addressNodes;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List<AddressNode> getAddressNodes() {
        return addressNodes;
    }

    @Override
    public String toString() {
        return "Node{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", url='" + url + '\'' +
                ", nodes=" + addressNodes +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AddressNode that = (AddressNode) o;
        return Objects.equals(id, that.id) &&
                Objects.equals(name, that.name) &&
                Objects.equals(url, that.url);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, url);
    }
}

interface SourceNode {
    /**
     * 获取源Node必须包含id(原则上是最精确的的那个)
     *
     * @return 源Node必须包含id(原则上是最精确的的那个)
     */
    String getId();

    /**
     * 获取源Node必须包含的url(最精确的区域对应的url)
     *
     * @return 源Node必须包含的url(最精确的区域对应的url)
     */
    String getUrl();
}

class SourceNodeImpl implements SourceNode {
    private String id;
    private String url;

    public SourceNodeImpl() {
    }

    public SourceNodeImpl(String id, String url) {
        this.id = id;
        this.url = url;
    }

    @Override
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "SourceNode{" +
                "code='" + id + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
}

class NodesCache {
    private final Map<String, AddressNode> nodesMap = new HashMap<>();

    public AddressNode cacheIfAbsent(AddressNode addressNode) {
        if (addressNode == null) {
            return null;
        }

        String id = addressNode.getId();

        if (!nodesMap.containsKey(id)) {
            nodesMap.put(id, addressNode);
        }

        return nodesMap.get(id);
    }

    public Collection<AddressNode> addressNodes() {
        return nodesMap.values();
    }
}